home *** CD-ROM | disk | FTP | other *** search
/ PC Users 1998 March / Pc Users extra 6.iso / pshare95 / prog / formula1 / vcform1.z / odbc2.frm (.txt) < prev    next >
Encoding:
Visual Basic Form  |  1997-09-22  |  16.4 KB  |  366 lines

  1. VERSION 4.00
  2. Begin VB.Form Form1 
  3.    Caption         =   "Double Click On Data in Location Tab for Drill Down"
  4.    ClientHeight    =   5175
  5.    ClientLeft      =   1365
  6.    ClientTop       =   1755
  7.    ClientWidth     =   6600
  8.    Height          =   5865
  9.    Icon            =   "odbc2.frx":0000
  10.    Left            =   1305
  11.    LinkTopic       =   "Form1"
  12.    ScaleHeight     =   5175
  13.    ScaleWidth      =   6600
  14.    Top             =   1125
  15.    Width           =   6720
  16.    Begin VB.Timer tmrInit 
  17.       Enabled         =   0   'False
  18.       Interval        =   500
  19.       Left            =   4020
  20.       Top             =   2640
  21.    End
  22.    Begin Threed.SSPanel StatusBar1 
  23.       Align           =   2  'Align Bottom
  24.       Height          =   315
  25.       Left            =   0
  26.       TabIndex        =   0
  27.       Top             =   4860
  28.       Width           =   6600
  29.       _Version        =   65536
  30.       _ExtentX        =   11642
  31.       _ExtentY        =   556
  32.       _StockProps     =   15
  33.       BackColor       =   12632256
  34.       BeginProperty Font {0BE35203-8F91-11CE-9DE3-00AA004BB851} 
  35.          Name            =   "MS Sans Serif"
  36.          Size            =   8.26
  37.          Charset         =   0
  38.          Weight          =   400
  39.          Underline       =   0   'False
  40.          Italic          =   0   'False
  41.          Strikethrough   =   0   'False
  42.       EndProperty
  43.       BevelOuter      =   0
  44.       BevelInner      =   1
  45.       Alignment       =   1
  46.    End
  47.    Begin VCF150Ctl.F1Book F1Book1 
  48.       Height          =   4635
  49.       Left            =   60
  50.       TabIndex        =   1
  51.       Top             =   120
  52.       Width           =   6435
  53.       _ExtentX        =   11351
  54.       _ExtentY        =   8176
  55.       _0              =   $"odbc2.frx":044A
  56.       _1              =   $"odbc2.frx":084F
  57.       _2              =   $"odbc2.frx":0C54
  58.       _3              =   $"odbc2.frx":1059
  59.       _4              =   $"odbc2.frx":145E
  60.       _count          =   5
  61.       _ver            =   1
  62.    End
  63.    Begin VB.Menu mnuFile 
  64.       Caption         =   "&File"
  65.       Begin VB.Menu mnuFileExit 
  66.          Caption         =   "E&xit"
  67.       End
  68.    End
  69.    Begin VB.Menu mnuDataAnalysis 
  70.       Caption         =   "&Data Analysis"
  71.       Begin VB.Menu mnuDataAnalysisType 
  72.          Caption         =   "&Sum"
  73.          Checked         =   -1  'True
  74.          Index           =   0
  75.          Tag             =   "SUM"
  76.       End
  77.       Begin VB.Menu mnuDataAnalysisType 
  78.          Caption         =   "&Average"
  79.          Index           =   1
  80.          Tag             =   "Average"
  81.       End
  82.       Begin VB.Menu mnuDataAnalysisType 
  83.          Caption         =   "Standard &Deviation"
  84.          Index           =   2
  85.          Tag             =   "STDEV"
  86.       End
  87.    End
  88.    Begin VB.Menu mnuHelp 
  89.       Caption         =   "Help!"
  90.    End
  91. Attribute VB_Name = "Form1"
  92. Attribute VB_Creatable = False
  93. Attribute VB_Exposed = False
  94. '' About the tables:
  95. ''    The ODBC2 database contains three tables:
  96. ''    Location_Table
  97. ''       ID          Counter
  98. ''       City        Text  50
  99. ''       State       Text  50
  100. ''       Region      Text  50
  101. ''    Employee_Table
  102. ''       ID          Counter
  103. ''       First_Name  Text  50
  104. ''       Last_Name   Text  50
  105. ''       Location    Integer
  106. ''    Sales_Table
  107. ''       ID          Counter
  108. ''       Date        dd-mmm-yy
  109. ''       Sales       Currency
  110. Option Explicit
  111. Dim DataSourceName$     ' Initialized in Form Load
  112. Dim DataConnectString$  ' Initialized in Form Load
  113. Private Sub F1Book1_DblClick(ByVal nRow As Long, ByVal nCol As Long)
  114.    '' This section implements the drill down aspect of the project. On startup, the
  115.    '' user will see the contents of the Location_Table. If they double click on a
  116.    '' column heading, a new sheet is added and a query based on the column header
  117.    '' is performed and loaded into the new sheet. If the user double clicks on a
  118.    '' cell, a new sheet is added, a query is made based on the contents of the cell
  119.    '' and placed in the sheet.
  120.    Dim query$, tabName$, funcNum%, i%
  121.    '' The queries look complex but were created in a minute by opening the ODBC2.MDB
  122.    '' in Access, creating the query with the query builder, switching to SQL mode,
  123.    '' and copying the result here. Although predefined queries would be faster, they
  124.    '' would require much more work and be much less flexible. First you would have
  125.    '' to generate queries for each item you would allow the use to drill on. Next
  126.    '' you would have to get the item the user clicked on and somehow transform that
  127.    '' into the name of the query you generated. Next you have to worry about records
  128.    '' being deleted, added, or modified. What happens if you add an employee or
  129.    '' location? Do you create new queries? Do you have to modify your code?.
  130.    '' The method used here avoids all this extra work at a relatively small
  131.    '' performance penalty.
  132.    ''
  133.    '' How to make the queries:
  134.    '' We know the tables as defined above. We also know that the first table they
  135.    '' see is the Location_Table so to start with, lets give the user a crosstab
  136.    '' that shows area versus date with sum of sales as the data. We do a bottom up
  137.    '' design and evolve it to fit our needs. Lets say the user clicks on the column
  138.    '' header for the city field in the Location_Table. To handle this case, first build
  139.    '' a crosstab in Access for city vs date and copy it here. This will handle the
  140.    '' case of the user double clicking in the City column header. If we replace single
  141.    '' occurance of city with the column header text the user clicked on (with ColText
  142.    '' method) we have a more versatile query that will fetch by city, state, or region.
  143.    ''
  144.    '' Now Evolve:
  145.    '' The above will generate 3 queries, but what if the user wants data for an
  146.    '' individual city. As a response, we can stick with the crosstab theme and provide
  147.    '' sales by person. Back to Access to build another query. We make this a crosstab
  148.    '' that shows Last_Name in the columns, date in rows, sum of sales as data, all
  149.    '' for the city of New Haven. Switch to SQL mode and copy the text here. For this
  150.    '' query we replace all occurances of City with the text from the column of the
  151.    '' cell the user clicked on and the occurance of New Haven with the text from the
  152.    '' cell the user double clicked on (TextRC method).
  153.    ''
  154.    '' SPECIAL NOTE: you use SINGLE QUOTES for a string in this query where Access
  155.    '' uses double quotes.
  156.    ''
  157.    '' How to tell which query to run? Simply check which row was double clicked on.
  158.    '' If nRow = 0, it was a column header so use the first query. Otherwise use the
  159.    '' second query.
  160.    ''
  161.    '' So now, with two "parameterized" queries in code below, we can generate 29
  162.    '' different sales crosstabs. Not too bad for this little function.
  163.    ''
  164.    '' Error Checking:
  165.    '' Of course we want some limit to the havoc the user can play with this simple
  166.    '' demo, so we limit the queries to double clicks in the data cells or the
  167.    '' column headers over the data cells.
  168.    With F1Book1
  169.       StatusBar1.Caption = "Adding New Sheet..."
  170.       StatusBar1.Refresh
  171.       
  172.       If .Sheet = 1 Then
  173.          If nRow <= .LastRow And nCol > 0 And nCol <= .LastCol Then
  174.             '' Crosstab of sales by City, State, Region if click on col header
  175.             If (nRow = 0) Then
  176.                Let query = "TRANSFORM Sum(Sales_Table.Sales) AS SumOfSales " & _
  177.                   "SELECT Sales_Table.Date FROM Sales_Table INNER JOIN " & _
  178.                   "(Employee_Table INNER JOIN Location_Table ON " & _
  179.                   "Employee_Table.Location = Location_Table.ID) ON " & _
  180.                   "Sales_Table.Employee = Employee_Table.ID GROUP BY " & _
  181.                   "Sales_Table.Date PIVOT Location_Table." & .ColText(nCol) & ";"
  182.                Let tabName = "Sales By " & .ColText(nCol)
  183.                .SetSelection 1, nCol, 1, nCol
  184.                StatusBar1.Caption = "Fetching Data for " & .ColText(nCol) & "..."
  185.             Else
  186.                '' Crosstab of area if clicked on cell
  187.                Let query = "TRANSFORM Sum(Sales_Table.Sales) AS SumOfSales " & _
  188.                   "SELECT Sales_Table.Date FROM Sales_Table INNER JOIN " & _
  189.                   "(Employee_Table INNER JOIN Location_Table ON Employee_Table.Location " & _
  190.                   "= Location_Table.ID) ON Sales_Table.Employee = Employee_Table.ID " & _
  191.                   "WHERE ((Location_Table." & .ColText(nCol) & " = '" & _
  192.                   .TextRC(nRow, nCol) & "')) GROUP BY Sales_Table.Date, " & _
  193.                   "Location_Table." & .ColText(nCol) & " PIVOT Employee_Table.Last_Name;"
  194.                Let tabName = "Sales In " & .TextRC(nRow, nCol)
  195.                StatusBar1.Caption = "Fetching Data for " & .TextRC(nRow, nCol) & "..."
  196.             End If
  197.             
  198.             StatusBar1.Refresh
  199.             
  200.             '' Add a sheet, make it active, set the tab name
  201.             .InsertSheets .NumSheets + 1, 1
  202.             .Sheet = .NumSheets
  203.             .SheetName(.Sheet) = tabName
  204.             
  205.             Call Fetch(F1Book1, .Sheet, 1, 1, DataConnectString, query, True, True, True, False)
  206.             '' Need to determine which data analysis to use
  207.             funcNum = 0
  208.             For i = 0 To 2
  209.                If mnuDataAnalysisType(i).Checked Then funcNum = i
  210.             Next i
  211.             StatusBar1.Caption = "Calculating Summary info and formatting..."
  212.             StatusBar1.Refresh
  213.             Call SetRowColCalc(F1Book1, mnuDataAnalysisType(funcNum).Tag, 1, .LastRow, 2, .LastCol)
  214.             '' LastCol is now the sum column
  215.             Call NameAndFormatColumn(F1Book1, .Sheet, .LastCol, "Total Sales", "$#,##0.00")
  216.             Call NameAndFormatColumn(F1Book1, .Sheet, 1, .ColText(1), "dd-mmm-yy")
  217.             Call NameAndFormatRow(F1Book1, .Sheet, .LastRow, "Total Sales", "$#,##0.00")
  218.             
  219.             Call FormatSalesCrossTab(F1Book1, .Sheet)
  220.          End If
  221.       End If
  222.       StatusBar1.Caption = "Ready..."
  223.    End With
  224. End Sub
  225. Private Sub Form_Load()
  226.    Let DataSourceName = "FO_ODBC2"
  227.    '' See Accessing External Databases in the VB4 help for
  228.    '' more info on creating this string (Professional Version).
  229.    '' When using this string in the ODBCConnect method, Formula
  230.    '' One will prompt for any information that is not provided by
  231.    '' either the data source or the string. For this project we
  232.    '' set all information for the data source with SQLConfigDataSource
  233.    '' and just tell Formula One to use ODBC and the data src name.
  234.    ''
  235.    '' These are done in a timer so the form can be refreshed and
  236.    '' the load time doesn't look so long. Two things take a while
  237.    '' to do - registering the database and getting an open
  238.    '' connection to it. After that everything is quite speedy.
  239.    '' You will probably want to hide this activity in a timer
  240.    '' also. The user will probably stare at the screen for three
  241.    '' or four seconds before starting anyway. Put up a help
  242.    '' screen or introduction to keep them busy.
  243.    Let DataConnectString = "ODBC;DSN=" & DataSourceName
  244.    '' Now start the timer for the help and the DSN and fetch
  245.    'tmrHelp.Enabled = True
  246.    tmrInit.Enabled = True
  247. End Sub
  248. Private Sub Form_Resize()
  249.    F1Book1.Width = ScaleWidth
  250.    F1Book1.Height = ScaleHeight - StatusBar1.Height
  251. End Sub
  252. Private Sub mnuDataAnalysisType_Click(Index As Integer)
  253. '' Indices are
  254. ''    0 Sum
  255. ''    1 Average
  256. ''    2 Standard Deviation
  257.    Dim i%
  258.    For i = 0 To 2
  259.       mnuDataAnalysisType(i).Checked = False
  260.    Next i
  261.    mnuDataAnalysisType(Index).Checked = True
  262.    If F1Book1.Sheet <> 1 Then
  263.       Call SetRowColCalc(F1Book1, mnuDataAnalysisType(Index).Tag, _
  264.          1, F1Book1.LastRow - 1, 2, F1Book1.LastCol - 1)
  265.       Call FormatSalesCrossTab(F1Book1, F1Book1.Sheet)
  266.    End If
  267.       
  268. End Sub
  269. Private Sub mnuFileExit_Click()
  270.    End
  271. End Sub
  272. Private Sub mnuHelp_Click()
  273.    Dim msg$
  274.    StatusBar1.Caption = "Helping..."
  275.    Let msg = "This data drill down example constructs queries on the fly " & _
  276.       "based on a double click on the spreadsheet with the tab name Location. " & _
  277.       "For example, double clicking on the column header named city will generate " & _
  278.       "a crosstab that shows sales in all cities over dates. A double click on " & _
  279.       "a cell containing New Haven will generate a query for all sales staff in " & _
  280.       "New Haven over dates covered in the database. " & Chr$(13) & Chr$(13) & _
  281.       "A new sheet is added to the workbook and filled with the query results. " & _
  282.       "The bottom row and right column contain simple data analysis whose default " & _
  283.       "is a sum. You can change this analysis for the active sheet and all future " & _
  284.       "by making a selection in Data Analysis menu."
  285.       
  286.    MsgBox msg
  287.    StatusBar1.Caption = "Ready..."
  288. End Sub
  289. Private Sub tmrInit_Timer()
  290.    Dim dbDriver$, dbAttributes$
  291.    Dim result As Boolean
  292.    tmrInit.Enabled = False
  293.    MousePointer = 11
  294.    '' The VB method DBEngine.RegisterDatabase will register
  295.    '' the data source name but not the database name or system
  296.    '' database name. There are four choices for doing this: Let
  297.    '' the user figure it out at run time, Write to the INI and
  298.    '' Registry yourself, Configure the data source ahead of time
  299.    '' with the ODBC admin 32 program, or use DLL calls as shown
  300.    '' in the example below. One warning - the VB DBEngine methods
  301.    '' are also very slow compared to the example below.
  302.    '' The following is left in as a curiosity...
  303.    '' Adds an entry to the ODBC.INI file and registry. Should be
  304.    '' done one time prior to use. Can be called every time
  305.    '' and only one entry will be made, but this slows load
  306.    '' time and destroys the settings for an existing
  307.    '' datasource that are made with the ODBC admin
  308.    '' 32 program (such as database name, system.mda).
  309.    'DBEngine.IniPath = App.Path & "\ODBC2.INI"
  310.    'DBEngine.RegisterDatabase DataSourceName, _
  311.       "Microsoft Access Driver (*.mdb) (32 bit)", _
  312.       True, "Driver32=C:\WINNT35\System32\odbcjt32.dll"
  313.    '' The following sets up a Data Source name and all the
  314.    '' attributes that are necessary to connect to the data
  315.    '' source without showing a dialog. The DSN is reconfigured
  316.    '' each time but this is pretty fast. The attributes must
  317.    '' be in null terminated keyword-value pairs with two nulls
  318.    '' at the end of the string.
  319.    '' Passing Form1.hWnd will generate a dialog for the user to
  320.    '' modify the info provided but, if you want the user to do
  321.    '' this, you can just use the Formula One generated dialogs
  322.    '' to create a new data source and skip all the dll stuff.
  323.    '' See odbc2.bas for more info.
  324.    StatusBar1.Caption = "Registering New Database..."
  325.    StatusBar1.Refresh
  326.    '' SQL Config DataSource use the text name to find the driver.
  327.    '' These are what my 32/16 bit drivers are installed as - yours
  328.    '' may have some slightly different name depending on where you
  329.    '' got them. Check the ODBC Admin program to find the name.
  330. #If Win32 Then
  331.    Let dbDriver = "Microsoft Access Driver (*.mdb)"
  332. #ElseIf Win16 Then
  333.    Let dbDriver = "Access Files (*.mdb)"
  334. #End If
  335.    Let dbAttributes = "DSN=" & DataSourceName & Chr$(0) _
  336.       & "DBQ=" & App.Path & "\ODBC2.MDB" & Chr$(0) _
  337.       & "SystemDB=" & App.Path & "\system.mda" & Chr$(0) _
  338.       & "DefaultDir=" & App.Path & Chr$(0) _
  339.       & "UID=admin" & Chr$(0) _
  340.       & "PWD=" & Chr$(0) & Chr$(0)
  341.    '' If the next statement fails, we can't get to the database without
  342.    '' the user going through some hoops, so we exit.
  343.    result = SQLCONFIGDATASOURCE(0, ODBC_ADD_DSN, dbDriver, dbAttributes)
  344.    If (False = result) Then
  345.       MsgBox "Establishing DSN failed!  Error: " & result
  346.       End
  347.    End If
  348.    StatusBar1.Caption = "Fetching Initial Table..."
  349.    StatusBar1.Refresh
  350.    '' Startup with the Location Table
  351.    Call Fetch(F1Book1, 1, 1, 1, DataConnectString, _
  352.       "Select City, State, Region From Location_Table", True, True, True, True)
  353.    Call MakeYellowGreenBars(F1Book1, 1)
  354.    With F1Book1
  355.       .Left = 0
  356.       .Top = 0
  357.       .SetSelection 1, 1, .LastRow, .LastCol
  358.       .SetBorder 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  359.       .Selection = "A1"
  360.       .SheetName(1) = "Locations"
  361.    End With
  362.    StatusBar1.Caption = "Ready..."
  363.    StatusBar1.Refresh
  364.    MousePointer = 0
  365. End Sub
  366.